/*
 * MIT License
 *
 * Copyright (c) 2019 Mr.css
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

package com.wendy.common.core.utils.reflect;

import com.esotericsoftware.reflectasm.MethodAccess;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

/**
 * 高效的Java反射工具类
 * <p>
 * field/setter/getter三者全部具备，才符合JavaBean的设计要求，
 * 特殊的业务场景下，setter、getter与field名称不是对应的，这时候，
 * 需要手动指定方法名，否则会导致Java反射失败。
 *
 * @author Mr.css
 * @version 2021-02-08 10:37
 */
public class ObjectField {

    /**
     * 字节码工具
     */
    private MethodAccess methodAccess;
    /**
     * 字段名称
     */
    private String name;
    /**
     * 字段对象实体类
     */
    private Field field;
    /**
     * 归属的Java类型
     */
    private Class<?> classType;
    /**
     * 字段类型
     */
    private Class<?> fieldType;
    /**
     * setter函数名
     * <p>
     * 特殊的JavaBean，getter与field名称可能不匹配，这种情况下，这个字段可能是空的，
     * 进行反射操作会抛出异常，这时候需要手动地把名称填上。
     */
    private String setter;
    /**
     * getter函数名
     * <p>
     * 特殊的JavaBean，getter与field名称可能不匹配，这种情况下，这个字段可能是空的，
     * 进行反射操作会抛出异常，这时候需要手动地把名称填上。
     */
    private String getter;
    /**
     * 对象类型
     */
    private ObjectType objectType;

    /**
     * 返回注解
     *
     * @param annotationClass 注解类型
     * @param <T>             泛型
     * @return 注解
     */
    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
        return field.getAnnotation(annotationClass);
    }

    /**
     * 返回注解
     *
     * @return 注解
     */
    public Annotation[] getAnnotations() {
        return field.getAnnotations();
    }

    /**
     * 设置值
     *
     * @param obj   目标对象
     * @param value 值
     */
    public void setValue(Object obj, Object value) {
        methodAccess.invoke(obj, setter, value);
    }

    /**
     * 获取值
     *
     * @param obj 目标对象
     */
    public Object getValue(Object obj) {
        return methodAccess.invoke(obj, getter);
    }

    //getter/setter-------------------------------------------------

    public MethodAccess getMethodAccess() {
        return methodAccess;
    }

    public void setMethodAccess(MethodAccess methodAccess) {
        this.methodAccess = methodAccess;
    }

    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    
    public Class<?> getClassType() {
        return classType;
    }

    public void setClassType(Class<?> classType) {
        this.classType = classType;
    }

    
    public Class<?> getFieldType() {
        return fieldType;
    }

    public void setFieldType(Class<?> fieldType) {
        this.fieldType = fieldType;
    }

    public String getSetter() {
        return setter;
    }

    public void setSetter(String setter) {
        this.setter = setter;
    }

    public String getGetter() {
        return getter;
    }

    public void setGetter(String getter) {
        this.getter = getter;
    }

    
    public Field getField() {
        return field;
    }

    public void setField(Field field) {
        this.field = field;
    }

    
    public ObjectType getObjectType() {
        return objectType;
    }

    public void setObjectType(ObjectType objectType) {
        this.objectType = objectType;
    }

    @Override
    public String toString() {
        return "ObjectField{" +
                "methodAccess=" + methodAccess +
                ", name='" + name + '\'' +
                ", field=" + field +
                ", classType=" + classType +
                ", fieldType=" + fieldType +
                ", setter='" + setter + '\'' +
                ", getter='" + getter + '\'' +
                ", objectType=" + objectType +
                '}';
    }
}
